package com.ncmmall.application.business.marketing;

import com.ncmmall.application.business.order.wechat.WechatRefundRequest;
import com.feijin.commons.domain.Ids;
import com.ncmmall.domain.business.goods.Goods;
import com.ncmmall.domain.business.goods.GoodsRepository;
import com.ncmmall.domain.business.goods.QGoods;
import com.ncmmall.domain.business.goods.sku.GoodsSku;
import com.ncmmall.domain.business.goods.sku.GoodsSkuRepository;
import com.ncmmall.domain.business.goods.sku.QGoodsSku;
import com.ncmmall.domain.business.marketing.gift.GiftActivity;
import com.ncmmall.domain.business.marketing.gift.GiftActivityRepository;
import com.ncmmall.domain.business.marketing.seckill.BargainGoods;
import com.ncmmall.domain.business.marketing.seckill.BargainGoodsRepository;
import com.ncmmall.domain.business.marketing.seckill.GroupBookingGoods;
import com.ncmmall.domain.business.marketing.seckill.GroupBookingGoodsRepository;
import com.ncmmall.domain.business.marketing.seckill.QSeckillActivity;
import com.ncmmall.domain.business.marketing.seckill.QSeckillGoods;
import com.ncmmall.domain.business.marketing.seckill.SeckillActivity;
import com.ncmmall.domain.business.marketing.seckill.SeckillActivityRepository;
import com.ncmmall.domain.business.marketing.seckill.SeckillGoods;
import com.ncmmall.domain.business.marketing.seckill.SeckillGoodsRepository;
import com.ncmmall.domain.business.marketing.seckill.SeckillSession;
import com.ncmmall.domain.business.marketing.seckill.SeckillSessionRepository;
import com.ncmmall.domain.business.order.Order;
import com.ncmmall.domain.business.order.OrderRepository;
import com.ncmmall.domain.business.order.groupbooking.GroupBooking;
import com.ncmmall.domain.business.order.groupbooking.GroupBookingOrder;
import com.ncmmall.domain.business.order.groupbooking.GroupBookingOrderRepository;
import com.ncmmall.domain.business.order.groupbooking.GroupBookingRepository;
import com.ncmmall.querychannel.service.QueryChannelService;
import com.google.common.collect.ImmutableMap;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 营销活动（秒杀、特价、预售、拼团、赠品）
 *
 * @author linxs
 * @date 2020-02-28 11:26
 */
@Service
@Transactional
public class MarketingApplication {

    @Autowired
    private SeckillSessionRepository seckillSessionRepository;

    @Autowired
    private SeckillActivityRepository seckillActivityRepository;

    @Autowired
    private GroupBookingRepository groupBookingRepository;

    @Autowired
    private GroupBookingOrderRepository groupBookingOrderRepository;

    @Autowired
    private GoodsRepository goodsRepository;

    @Autowired
    private OrderRepository orderRepository;

    @Autowired
    private GiftActivityRepository giftActivityRepository;

    @Autowired
    private GoodsSkuRepository skuRepository;

    @Autowired
    private QueryChannelService queryChannelService;

    @Autowired
    private SeckillGoodsRepository seckillGoodsRepository;

    @Autowired
    private BargainGoodsRepository bargainGoodsRepository;

    @Autowired
    private GroupBookingGoodsRepository groupBookingGoodsRepository;

    /**
     * 营销活动定时任务（执行频率：每分钟）
     */
    public void marketingJob() {

        String currDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String currTime = new SimpleDateFormat("HH:mm").format(new Date());

        //赠品活动
        beginGiftActivity(currDate + " " + currTime);
        endGiftActivity(currDate + " " + currTime);

        //秒杀活动
        beginSeckill();
        endSeckill();

        //特价活动
        beginBargain(currDate, currTime);
        endBargain(currDate, currTime);

        //拼团活动
        beginGroupBooking(currDate + " " + currTime);
        endGroupBooking(currDate + " " + currTime);

        //预售活动
        beginPresell(currDate + " " + currTime);
        endPresell(currDate + " " + currTime);

    }

    /**
     * 赠品活动结束
     */
    private void endGiftActivity(String currDate) {
        List<GiftActivity> giftActivities = queryChannelService.findAll("select g from GiftActivity g where g.isValidity != 3 and g.endDateOfValidity <= :time ", ImmutableMap.of("time", currDate), GiftActivity.class);
        for (GiftActivity giftActivity : giftActivities) {
            if (giftActivity.getStatus() == 1) {
                giftActivity.setStatus(2);
            }
            giftActivity.setIsValidity(3);
            giftActivityRepository.save(giftActivity);
        }
    }

    /**
     * 赠品活动开始
     */
    private void beginGiftActivity(String currDate) {
        List<GiftActivity> giftActivities = queryChannelService.findAll("select g from GiftActivity g where g.status = 1 and g.isValidity = 1 and g.beginDateOfValidity <= :time ", ImmutableMap.of("time", currDate), GiftActivity.class);
        for (GiftActivity giftActivity : giftActivities) {
            giftActivity.setIsValidity(2);
            giftActivityRepository.save(giftActivity);
        }
    }

    /**
     * 预售尾款开始与截止
     */
    private void endPresell(String currDateTime) {

        //尾款开始支付且定金截止支付的商品
        List<Goods> goodses = queryChannelService.findAll("select g from Goods g where g.marketingType = 3 and g.presellRetainagePayBeginTime <= :time and g.presellStatus=6 ", ImmutableMap.of("time", currDateTime), Goods.class);
        for (Goods goodse : goodses) {
            goodse.setPresellStatus(7); //尾款开始支付
            goodse.setMarketingType(0); //普通商品
            goodsRepository.save(goodse);

            List<Order> orders = queryChannelService.findAll("select d.order from OrderDetail d where d.sku.goods.id = :id and d.order.marketingType=5 and d.order.status = 7 ", ImmutableMap.of("id", goodse.getId()), Order.class);
            for (Order order : orders) {
                order.setStatus(8);//等待支付尾款
                orderRepository.save(order);
            }
        }

        //预售尾款截止时间到
        List<Goods> endPayGoodses = queryChannelService.findAll("select g from Goods g where g.marketingType = 0 and g.presellRetainagePayEndTime <= :time and g.presellStatus=7 ", ImmutableMap.of("time", currDateTime), Goods.class);
        for (Goods goodse : endPayGoodses) {
            goodse.setPresellStatus(8);
            goodsRepository.save(goodse);

            List<Order> orders = queryChannelService.findAll("select d.order from OrderDetail d where d.sku.goods.id = :id and d.order.marketingType=5 and d.order.status = 8 ", ImmutableMap.of("id", goodse.getId()), Order.class);
            for (Order order : orders) {
                order.setStatus(6); //取消订单
                orderRepository.save(order);

                // 返还商品库存，减少商品销量
                goodse.setStore(goodse.getStore() + order.getDetails().get(0).getQuantity());
                goodse.setSalesVolume(goodse.getSalesVolume() - order.getDetails().get(0).getQuantity());
                goodsRepository.save(goodse);

                GoodsSku sku = queryChannelService.findOne(QGoodsSku.goodsSku.id.eq(order.getDetails().get(0).getSku().getId()), GoodsSku.class);
                sku.setStore(sku.getStore() + order.getDetails().get(0).getQuantity());
                skuRepository.save(sku);

            }


        }

    }

    /**
     * 预售订金开始与截止
     */
    private void beginPresell(String currDateTime) {

        List<Goods> goodses = queryChannelService.findAll("select g from Goods g where g.marketingType = 3 and g.presellSubscriptionPayBeginTime <= :time and g.presellStatus=3 ", ImmutableMap.of("time", currDateTime), Goods.class);
        for (Goods goodse : goodses) {
            goodse.setPresellStatus(5);
            goodsRepository.save(goodse);
        }

        //预售订金截止时间到
        List<Goods> endPayGoodses = queryChannelService.findAll("select g from Goods g where g.marketingType = 3 and g.presellSubscriptionPayEndTime <= :time and g.presellStatus=5 ", ImmutableMap.of("time", currDateTime), Goods.class);
        for (Goods goodse : endPayGoodses) {
            goodse.setPresellStatus(6);
            goodsRepository.save(goodse);


            //取消掉未付款的预售订单
            List<Order> cancelOrders = queryChannelService.findAll("select d.order from OrderDetail d where d.order.marketingType=5 and d.order.payStatus = 2 and d.order.status = 1 and  d.sku.goods.id = :gid ", ImmutableMap.of("gid", goodse.getId()), Order.class);
            for (Order cancelOrder : cancelOrders) {
                cancelOrder.setStatus(6);
                orderRepository.save(cancelOrder);

                // 返还商品库存，减少商品销量
                Goods goods = cancelOrder.getDetails().get(0).getSku().getGoods();
                goods.setStore(goods.getStore() + cancelOrder.getDetails().get(0).getQuantity());
                goods.setSalesVolume(goods.getSalesVolume() - cancelOrder.getDetails().get(0).getQuantity());
                goods.setPresellSalesVolume(goods.getPresellSalesVolume() - cancelOrder.getDetails().get(0).getQuantity());

                GoodsSku sku = queryChannelService.findOne(QGoodsSku.goodsSku.eq(cancelOrder.getDetails().get(0).getSku()), GoodsSku.class);
                sku.setStore(sku.getStore() + cancelOrder.getDetails().get(0).getQuantity());
                goodsRepository.save(goods);

            }
        }

    }

    /**
     * 拼团结束
     *
     * @param currDate
     */
    private void endGroupBooking(String currDate) {
        List<Goods> goodses = queryChannelService.findAll("select g from Goods g where g.marketingType = 4 and g.groupBookingStatus = 5 and g.groupBookingEndTime <= :currdate ", ImmutableMap.of("currdate", currDate), Goods.class);
        for (Goods goodse : goodses) {
            goodse.setGroupBookingStatus(6);

            GroupBookingGoods groupBookingGoods = new GroupBookingGoods();
            groupBookingGoods.setCreateTime(new Timestamp(System.currentTimeMillis()));
            groupBookingGoods.setGoods(goodse);
            groupBookingGoods.setGroupBookingTotal(goodse.getGroupBookingTotal());
            groupBookingGoods.setGroupBookingStore(goodse.getGroupBookingStore());
            groupBookingGoods.setGroupBookingStatus(goodse.getGroupBookingStatus());
            groupBookingGoods.setGroupBookingSalesVolume(goodse.getGroupBookingSalesVolume());
            groupBookingGoods.setGroupBookingPrice(goodse.getGroupBookingPrice());
            groupBookingGoods.setGroupBookingLimit(groupBookingGoods.getGroupBookingLimit());
            groupBookingGoods.setGroupBookingEndTime(groupBookingGoods.getGroupBookingEndTime());
            groupBookingGoods.setGroupBookingCondition(groupBookingGoods.getGroupBookingCondition());
            groupBookingGoods.setGroupBookingBeginTime(groupBookingGoods.getGroupBookingBeginTime());
            groupBookingGoodsRepository.save(groupBookingGoods);

            goodse.setMarketingType(0);
            goodsRepository.save(goodse);
        }

        List<GroupBooking> groupBookings = queryChannelService.findAll("select g from GroupBooking g where g.status = 1 and g.endTime <= :currtime ", ImmutableMap.of("currtime", currDate), GroupBooking.class);
        for (GroupBooking groupBooking : groupBookings) {
            groupBooking.setStatus(3);
            groupBookingRepository.save(groupBooking);

            for (GroupBookingOrder order : groupBooking.getDetails()) {
                if (order.getStatus() == 2) {
                    order.setOutRefundNo(Ids.generateId());
                    Map<String, String> refundResult = new WechatRefundRequest(order.getPayNo(), order.getPrice(), order.getPrice(), order.getOutRefundNo()).refundByWechatMp();
                    if (refundResult.get("flag").equals("true")) {
                        order.setStatus(4);
                        groupBookingOrderRepository.save(order);
                    } else {
                        throw new RuntimeException("[微信退款失败] " + refundResult.get("message"));
                    }
                }
            }
        }
    }

    /**
     * 拼团开始
     *
     * @param currDate
     */
    private void beginGroupBooking(String currDate) {
        List<Goods> goodses = queryChannelService.findAll("select g from Goods g where g.marketingType = 4 and g.groupBookingStatus = 3 and g.groupBookingBeginTime <= :currdate ", ImmutableMap.of("currdate", currDate), Goods.class);
        for (Goods goodse : goodses) {
            goodse.setGroupBookingStatus(5);
            goodsRepository.save(goodse);
        }
    }

    /**
     * 特价结束
     *
     * @param currDate 当前日期
     * @param currTime 当前时间
     */
    private void endBargain(String currDate, String currTime) {

        List<Goods> goodses = queryChannelService.findAll("select g from Goods g where g.marketingType = 1 and g.endDateOfValidity <= :endtime ", ImmutableMap.of("endtime", currDate + " " + currTime), Goods.class);

        for (Goods goodse : goodses) {

            //保存特价商品记录
            BargainGoods bargainGoods = new BargainGoods();
            bargainGoods.setGoods(goodse);
            bargainGoods.setBeginDateOfValidity(goodse.getBeginDateOfValidity());
            bargainGoods.setEndDateOfValidity(goodse.getEndDateOfValidity());
            bargainGoods.setBargainPrice(goodse.getBargainPrice());
            bargainGoods.setBargainStore(goodse.getBargainStore());
            bargainGoods.setBargainSalesVolume(goodse.getSalesVolume());
            bargainGoodsRepository.save(bargainGoods);

            goodse.setMarketingType(0);
            goodse.setBargainStatus(0);
            goodsRepository.save(goodse);
        }
    }

    /**
     * 特价开始
     */
    private void beginBargain(String currDate, String currTime) {

        List<Goods> goodses = queryChannelService.findAll("select g from Goods g where g.marketingType = 1 and g.bargainStatus = 3 and g.beginDateOfValidity <= :begintime ", ImmutableMap.of("begintime", currDate + " " + currTime), Goods.class);
        for (Goods goodse : goodses) {
            goodse.setBargainStatus(5);
            goodsRepository.save(goodse);
        }

    }

    /**
     * 秒杀结束
     */
    private void endSeckill() {

        List<SeckillSession> sessions = queryChannelService.findAll("select s from SeckillSession s where s.isValidity = 2", SeckillSession.class);
        Timestamp now = new Timestamp(System.currentTimeMillis());

        for (SeckillSession session : sessions) {

            String seckillTime = session.getSeckillTime();
            String endTime = session.getSeckillEndTime();

            Timestamp end;
            if (StringUtils.length(endTime) == 8) {
                end = Timestamp.valueOf(seckillTime + " " + endTime);
            } else {
                end = Timestamp.valueOf(seckillTime + " " + endTime + ":00");
            }

            if (end.before(now)) {
                //过期了
                session.setIsValidity(3);
                seckillSessionRepository.save(session);

                //查询所有参与该秒杀场次的活动
                List<SeckillActivity> activities = queryChannelService.findAll(QSeckillActivity.seckillActivity.seckillSession.id.eq(session.getId()), SeckillActivity.class);
                for (SeckillActivity activity : activities) {
                    activity.setIsValidity(3);
                    seckillActivityRepository.save(activity);
                }

                //查询所有参与该秒杀场次的商品
                List<Goods> goodsList = queryChannelService.findAll(QGoods.goods.marketingType.eq(2).and(QGoods.goods.seckillSession.id.eq(session.getId())), Goods.class);
                for (Goods goods : goodsList) {

                    //保存此次秒杀数据
                    SeckillActivity activity = queryChannelService.findOne(QSeckillActivity.seckillActivity.merchant.id.eq(goods.getMerchant().getId()).and(QSeckillActivity.seckillActivity.seckillSession.id.eq(session.getId())), SeckillActivity.class);
                    SeckillGoods seckillGoods = queryChannelService.findOne(QSeckillGoods.seckillGoods.goods.id.eq(goods.getId()).and(QSeckillGoods.seckillGoods.seckillActivity.id.eq(activity.getId())), SeckillGoods.class);

                    if (seckillGoods != null) {
                        seckillGoods.setSeckillPrice(goods.getSeckillPrice());
                        seckillGoods.setSeckillStore(goods.getSeckillStore());
                        seckillGoods.setSeckillSalesVolume(goods.getSeckillSalesVolume());
                        seckillGoodsRepository.save(seckillGoods);
                    }

                    goods.setMarketingType(0);
                    goods.setSeckillStatus(6);
                    goods.setSeckillPrice(0);
                    goods.setSeckillStore(0);
                    goods.setSeckillSalesVolume(0);
                    goodsRepository.save(goods);
                }
            }
        }
    }

    /**
     * 秒杀开始
     */
    private void beginSeckill() {

        List<SeckillSession> sessions = queryChannelService.findAll("select s from SeckillSession s where s.isValidity = 1 or s.isValidity = 2", SeckillSession.class);
        Timestamp now = new Timestamp(System.currentTimeMillis());

        for (SeckillSession session : sessions) {

            String seckillTime = session.getSeckillTime();
            String beginTime = session.getSeckillBeginTime();

            Timestamp begin;
            if (StringUtils.length(beginTime) == 8) {
                begin = Timestamp.valueOf(seckillTime + " " + beginTime);
            } else {
                begin = Timestamp.valueOf(seckillTime + " " + beginTime + ":00");
            }

            if (begin.before(now)) {
                //活动该启动了
                if (session.getIsValidity() == 1) {
                    session.setIsValidity(2);
                    seckillSessionRepository.save(session);
                }

                //查询所有参与该秒杀场次的活动
                List<SeckillActivity> activities = queryChannelService.findAll(QSeckillActivity.seckillActivity.seckillSession.id.eq(session.getId()), SeckillActivity.class);
                for (SeckillActivity activity : activities) {
                    if (activity.getIsValidity() == 1) {
                        activity.setIsValidity(2);
                        seckillActivityRepository.save(activity);
                    }
                }

                //查询所有参与该秒杀场次的商品
                List<Goods> goodsList = queryChannelService.findAll(QGoods.goods.marketingType.eq(2).and(QGoods.goods.seckillSession.id.eq(session.getId())), Goods.class);
                for (Goods goods : goodsList) {
                    if (goods.getSeckillStatus() != 5) {
                        goods.setSeckillStatus(5);
                        goodsRepository.save(goods);
                    }
                }
            }
        }
    }
}
